/*! \file
 * \brief Enter a brief description here.
 *
 * Enter a detailed description here. (optional)
 * \author Author (Ivo Wingelaar)
 * \date Date (2011)
 * \version Version (0.0.1)
 * \copyright Copyright (GNU LGPL v3)
 */

#ifndef __LYNX_TEXTURE_C_HPP_INCLUDED__
#define __LYNX_TEXTURE_C_HPP_INCLUDED__

#include "LynxConfig.hpp"
#include "LynxTexture.hpp"
#include "LynxImage.hpp"

#define GL_GLEXT_LEGACY 1
#include <GL/gl.h>

#ifdef _LYNX_WINDOWS_
// include windows headers for HWND
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif

namespace Lynx
{

class VideoManager_C;

//! OpenGL texture.
class Texture_C : public Texture
{
public:
    //! constructor
    Texture_C(Image* surface, const std::string name, void* mipmapData = 0, VideoManager_C* driver = 0);

    //! destructor
    virtual ~Texture_C();

    //! lock function
    virtual void* lock(bool readOnly = false, uint32_t mipmapLevel=0);

    //! unlock function
    virtual void unlock();

    //! Returns original size of the texture (image).
    virtual const Myth::Math::Vector2u get_original_size() const;

    //! Returns size of the texture.
    virtual const Myth::Math::Vector2u get_size() const;

    //! returns color format of texture
    virtual E_COLOR_FORMAT get_color_format() const;

    //! returns pitch of texture (in bytes)
    virtual uint32_t get_pitch() const;

    //! Returns if the texture has an alpha channel
    virtual bool has_alpha() const;

    //! return open gl texture name
    GLuint getOpenGLTextureName() const;

    //! return whether this texture has mipmaps
    virtual bool has_mip_maps() const;

    //! Regenerates the mip map levels of the texture.
    /** Useful after locking and modifying the texture
    \param mipmapData Pointer to raw mipmap data, including all necessary mip levels, in the same format as the main texture image. If not set the mipmaps are derived from the main image. */
    virtual void regenerate_mip_map_levels(void* mipmapData = 0);

    //! Is it a render target?
    virtual bool is_render_target() const;

    //! Is it a FrameBufferObject?
    virtual bool isFrameBufferObject() const;

    //! Bind RenderTargetTexture
    virtual void bindRTT();

    //! Unbind RenderTargetTexture
    virtual void unbindRTT();

    //! sets whether this texture is intended to be used as a render target.
    void setIsRenderTarget(bool isTarget);

    virtual const std::string get_name() const;

    virtual void set_name(std::string name);

    virtual void make_color_key_texture(Color color, bool zeroTexels = false);

    virtual void make_color_key_texture(Myth::Math::Vector2i colorKeyPixelPos, bool zeroTexels = false);

    virtual void make_normal_map_texture(float amplitude = 1.0f);

protected:
    //! protected constructor with basic setup, no GL texture name created, for derived classes
    Texture_C(const std::string name, VideoManager_C* driver);

    //! get the desired color format based on texture creation flags and the input format.
    E_COLOR_FORMAT getBestColorFormat(E_COLOR_FORMAT format);

    //! Get the OpenGL color format parameters based on the given Irrlicht color format
    GLint getOpenGLFormatAndParametersFromColorFormat(E_COLOR_FORMAT format, GLint& filtering, GLenum& colorformat, GLenum& type);

    //! get important numbers of the image and hw texture
    void getImageValues(Image* image);

    //! copies the texture into an OpenGL texture.
    /** \param newTexture True if method is called for a newly created texture for the first time. Otherwise call with false to improve memory handling.
    \param mipmapData Pointer to raw mipmap data, including all necessary mip levels, in the same format as the main texture image.
    \param mipLevel If set to non-zero, only that specific miplevel is updated, using the MipImage member. */
    void uploadTexture(bool newTexture = false, void* mipmapData = 0, uint32_t mipLevel = 0);

    Myth::Math::Vector2u mImageSize;
    Myth::Math::Vector2u mTextureSize;
    E_COLOR_FORMAT mColorFormat;
    VideoManager_C* mDriver;
    Image* mImage;
    Image* mMipImage;

    GLuint mTextureName;
    GLint mInternalFormat;
    GLenum mPixelFormat;
    GLenum mPixelType;

    std::string mName;
    uint8_t mMipLevelStored;
    bool mHasMipMaps;
    bool mIsRenderTarget;
    bool mAutomaticMipmapUpdate;
    bool mReadOnlyLock;
    bool mKeepImage;
};

//! OpenGL FBO texture.
class TextureFBO_C : public Texture_C
{
public:

    //! FrameBufferObject constructor
    TextureFBO_C(const Myth::Math::Vector2u size, const std::string name, VideoManager_C* driver = 0, const E_COLOR_FORMAT format = ECF_UNKNOWN);

    //! destructor
    virtual ~TextureFBO_C();

    //! Is it a FrameBufferObject?
    virtual bool isFrameBufferObject() const;

    //! Bind RenderTargetTexture
    virtual void bindRTT();

    //! Unbind RenderTargetTexture
    virtual void unbindRTT();

    Texture* mDepthTexture;
protected:
    GLuint mColorFrameBuffer;
};


//! OpenGL FBO depth texture.
class TextureFBODepth_C : public TextureFBO_C
{
public:
    //! FrameBufferObject depth constructor
    TextureFBODepth_C(const Myth::Math::Vector2u size, const std::string name, VideoManager_C* driver = 0, bool useStencil = false);

    //! destructor
    virtual ~TextureFBODepth_C();

    //! Bind RenderTargetTexture
    virtual void bindRTT();

    //! Unbind RenderTargetTexture
    virtual void unbindRTT();

    bool attach(Texture*);

protected:
    GLuint mDepthRenderBuffer;
    GLuint mStencilRenderBuffer;
    bool mUseStencil;
};

} // namespace Lynx

#endif // __LYNX_TEXTURE_C_HPP_INCLUDED__

